package com.kingyea.gradle.jsch.command;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.kingyea.gradle.CommandExecutionException;
import com.kingyea.gradle.jsch.JschSession;

public class ExecCommandExecutor implements CommandExecutor {
	private JschSession session;
	
	public ExecCommandExecutor(JschSession session) {
		this.session = session;
	}

	@Override
	public ExecuteResult execute(String command) throws JSchException, IOException {
		ChannelExec channel = this.session.getExecChannel();
		channel.setCommand(command);
		channel.setInputStream(null);
		ByteArrayOutputStream stdOut = new ByteArrayOutputStream();
		ByteArrayOutputStream stdErr = new ByteArrayOutputStream();
		channel.setOutputStream(stdOut);
		channel.setErrStream(stdErr);
		channel.connect();
		try {
			ExecuteResult result = fetchResult(channel);
			result.setStdout(new String(stdOut.toByteArray()));
			result.setStderr(new String(stdErr.toByteArray()));
			return result;
		} catch (CommandExecutionException e) {
			System.out.println(String.format("command: %s execution timeout.", command));
		}
		return null;
	}
	
	private ExecuteResult fetchResult(ChannelExec channel) throws IOException {
		boolean fetched = false;
		ExecuteResult result = new ExecuteResult(Integer.MIN_VALUE, null, null);
		InputStream in = channel.getInputStream();
		for(int j=0; j<session.getTimeout(); j+=1000) {
			if (in.available() > 0) {
				StringBuilder resultString = new StringBuilder();				
				BufferedReader reader = new BufferedReader(new InputStreamReader(in));
				String line = null;
				while((line=reader.readLine())!=null) {
					resultString.append(line).append('\n');
				}
				if(resultString.length()>0) {
					resultString.deleteCharAt(resultString.length()-1);
				}
				result.setResult(resultString.toString());
				result.setExitCode(channel.getExitStatus());
				channel.disconnect();
				fetched = true;
				break;
			}
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
			}
		}
		
		if(!fetched) {
			throw new CommandExecutionException();
		}
		return result;
	}

	@Override
	public void close() throws IOException {
		this.session.close();		
	}

}
